from __future__ import absolute_import

from file_parser import *
from make_file_base import *

def make_cpptoc_impl_proto(name, func, parts, flag):
  if isinstance(func, obj_function_virtual):
    proto = parts['retval'] + ' ARK_WEB_CALLBACK'
  elif flag:
    proto = 'ARK_WEB_EXPORT ' + parts['retval']
  else:
    proto = parts['retval']

  proto += ' ' + name + '(' + ', '.join(parts['args']) + ')'
  return proto


def make_cpptoc_function_impl_new(cls, name, func, defined_names):
  # retrieve the C API prototype parts
  parts = func.get_capi_parts(defined_names, True)
  result = make_cpptoc_impl_proto(name, func, parts, False) + ' {'

  invalid = []

  # retrieve the function arguments
  args = func.get_arguments()

  # determine the argument types
  for arg in args:
    if arg.get_arg_type() == 'invalid':
      invalid.append(arg.get_name())

  # retrieve the function return value
  retval = func.get_retval()
  retval_type = retval.get_retval_type()
  if retval_type == 'invalid':
    invalid.append('(return value)')
    retval_default = ''
  else:
    retval_default = retval.get_retval_default(True)
    if len(retval_default) > 0:
      retval_default = ' ' + retval_default

  if len(invalid) > 0:
    notify(name + ' could not be autogenerated')
    # code could not be auto-generated
    result += '\n  // BEGIN DELETE BEFORE MODIFYING'
    result += '\n  // AUTO-GENERATED CONTENT'
    result += '\n  // COULD NOT IMPLEMENT DUE TO: ' + ', '.join(invalid)
    result += '\n  #pragma message("Warning: " __FILE__ ": ' + name + ' is not implemented")'
    result += '\n  // END DELETE BEFORE MODIFYING'
    result += '\n}\n\n'
    return result

  result_len = len(result)

  optional = []

  # parameter verification
  if isinstance(func, obj_function_virtual):
    result += '\n  ARK_WEB_CPPTOC_DV_LOG(\"capi struct is %{public}ld\", (long)self);\n'
    result += '\n  ARK_WEB_CPPTOC_CHECK_PARAM(self, ' + retval_default + ');\n'

  for arg in args:
    arg_type = arg.get_arg_type()
    arg_name = arg.get_type().get_name()

    # skip optional params
    optional_params = arg.parent.get_attrib_list('optional_param')
    if not optional_params is None and arg_name in optional_params:
      optional.append(arg_name)
      continue

    comment = '\n  // Verify param: ' + arg_name + '; type: ' + arg_type

    if arg_type == 'simple_byref' or arg_type == 'simple_byref_const' or \
       arg_type == 'simple_byaddr' or arg_type == 'bool_byref' or arg_type == 'bool_byaddr' or \
       arg_type == 'struct_byref_const' or arg_type == 'struct_byref' or \
       arg_type == 'string_byref_const' or arg_type == 'string_byref' or \
       arg_type == 'refptr_diff_byref' or \
       arg_type == 'ownptr_diff' or arg_type == 'ownptr_diff_byref' or \
       arg_type == 'rawptr_same' or arg_type == 'rawptr_same_byref' or \
       arg_type == 'rawptr_diff' or arg_type == 'rawptr_diff_byref' or \
       arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const' or \
       arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const' or \
       arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const':
      if arg_name[0] == '*':
        result += '\n  ARK_WEB_CPPTOC_CHECK_PARAM(' + arg_name[1:] + ', ' + retval_default + ');\n'
      else:
        result += '\n  ARK_WEB_CPPTOC_CHECK_PARAM(' + arg_name + ', ' + retval_default + ');\n'
      if arg_type == 'struct_byref_const' or arg_type == 'struct_byref':
        result +=\
                '\n  if (!template_util::has_valid_size('+arg_name+')) {'\
                '\n    return'+retval_default+';'\
                '\n  }'
    elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
        arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref' or \
        arg_type == 'ownptr_vec_same_byref' or arg_type == 'ownptr_vec_diff_byref' or \
        arg_type == 'rawptr_vec_same_byref' or arg_type == 'rawptr_vec_diff_byref':
      result += comment+\
                '\n  if (!'+arg_name+'Count || (*'+arg_name+'Count > 0 && !'+arg_name+')) {'\
                '\n    return'+retval_default+';'\
                '\n  }'
    elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
        arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
        arg_type == 'ownptr_vec_same_byref_const' or arg_type == 'ownptr_vec_diff_byref_const' or \
        arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
      result += comment+\
                '\n  if ('+arg_name+'Count > 0 && !'+arg_name+') {'\
                '\n    return'+retval_default+';'\
                '\n  }'

    # check index params
    index_params = arg.parent.get_attrib_list('index_param')
    if not index_params is None and arg_name in index_params:
      result += comment+\
                '\n  if ('+arg_name+' < 0) {'\
                '\n    return'+retval_default+';'\
                '\n  }'

  if len(optional) > 0:
    # Wrap the comment at 80 characters.
    str = '\n  // Unverified params: ' + optional[0]
    for name in optional[1:]:
      str += ','
      if len(str) + len(name) + 1 > 80:
        result += str
        str = '\n  //'
      str += ' ' + name
    result += str

  if len(result) != result_len:
    result += '\n'
  result_len = len(result)

  # parameter translation
  params = []

  for arg in args:
    arg_type = arg.get_arg_type()
    arg_name = arg.get_type().get_name()

    comment = '\n  // Translate param: ' + arg_name + '; type: ' + arg_type

    if arg_type == 'simple_byval' or arg_type == 'simple_byaddr':
      if arg_name[0] == '*':
        params.append(arg_name[1:])
      else:
        params.append(arg_name)
    elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const':
      params.append('*' + arg_name)
    elif arg_type == 'bool_byval':
      params.append(arg_name)
    elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr':
      params.append('*' + arg_name)
    elif arg_type == 'struct_byref_const':
      struct_type = arg.get_type().get_type()
      result += comment+\
                '\n  '+struct_type+' '+arg_name+'Obj;'\
                '\n  if ('+arg_name+') {'\
                '\n    '+arg_name+'Obj.Set(*'+arg_name+', false);'\
                '\n  }'
      params.append(arg_name + 'Obj')
    elif arg_type == 'struct_byref':
      struct_type = arg.get_type().get_type()
      result += comment+\
                '\n  '+struct_type+' '+arg_name+'Obj;'\
                '\n  if ('+arg_name+') {'\
                '\n    '+arg_name+'Obj.AttachTo(*'+arg_name+');'\
                '\n  }'
      params.append(arg_name + 'Obj')
    elif arg_type == 'string_byref_const':
      params.append('CefString(' + arg_name + ')')
    elif arg_type == 'string_byref':
      result += comment+\
                '\n  CefString '+arg_name+'Str('+arg_name+');'
      params.append(arg_name + 'Str')
    elif arg_type == 'refptr_same' or arg_type == 'refptr_diff':
      ptr_class = arg.get_type().get_ptr_type()
      if arg_type == 'refptr_same':
        params.append(ptr_class + 'CppToC::Revert(' + arg_name + ')')
      else:
        params.append(ptr_class + 'CToCpp::Invert(' + arg_name + ')')
    elif arg_type == 'ownptr_same' or arg_type == 'rawptr_same':
      ptr_class = arg.get_type().get_ptr_type()
      if arg_type == 'ownptr_same':
        params.append(ptr_class + 'CppToC::UnwrapOwn(' + arg_name + ')')
      else:
        params.append(ptr_class + 'CppToC::UnwrapRaw(' + arg_name + ')')
    elif arg_type == 'ownptr_diff' or arg_type == 'rawptr_diff':
      ptr_class = arg.get_type().get_ptr_type()
      result += comment+\
                '\n  CefOwnPtr<'+ptr_class+'> '+arg_name+'Ptr('+ptr_class+'CToCpp::Invert('+arg_name+'));'
      if arg_type == 'ownptr_diff':
        params.append('std::move(' + arg_name + 'Ptr)')
      else:
        params.append(arg_name + 'Ptr.get()')
    elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
      ptr_class = arg.get_type().get_ptr_type()
      if arg_type == 'refptr_same_byref':
        assign = ptr_class + 'CppToC::Revert(*' + arg_name + ')'
      else:
        assign = ptr_class + 'CToCpp::Invert(*' + arg_name + ')'
      result += comment+\
                '\n  ArkWebRefPtr<'+ptr_class+'> '+arg_name+'Ptr;'\
                '\n  if ('+arg_name+' && *'+arg_name+') {'\
                '\n    '+arg_name+'Ptr = '+assign+';'\
                '\n  }'\
                '\n  '+ptr_class+'* '+arg_name+'Orig = '+arg_name+'Ptr.get();'
      params.append(arg_name + 'Ptr')
    elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const':
      result += comment+\
                '\n  std::vector<CefString> '+arg_name+'List;'\
                '\n  transfer_string_list_contents('+arg_name+', '+arg_name+'List);'
      params.append(arg_name + 'List')
    elif arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const':
      result += comment+\
                '\n  std::map<CefString, CefString> '+arg_name+'Map;'\
                '\n  transfer_string_map_contents('+arg_name+', '+arg_name+'Map);'
      params.append(arg_name + 'Map')
    elif arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const':
      result += comment+\
                '\n  std::multimap<CefString, CefString> '+arg_name+'Multimap;'\
                '\n  transfer_string_multimap_contents('+arg_name+', '+arg_name+'Multimap);'
      params.append(arg_name + 'Multimap')
    elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
        arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
      vec_type = arg.get_type().get_vector_type()
      if arg_type == 'simple_vec_byref':
        assign = arg_name + '[i]'
      elif arg_type == 'bool_vec_byref':
        assign = arg_name + '[i]?true:false'
      elif arg_type == 'refptr_vec_same_byref':
        ptr_class = arg.get_type().get_ptr_type()
        assign = ptr_class + 'CppToC::Revert(' + arg_name + '[i])'
      elif arg_type == 'refptr_vec_diff_byref':
        ptr_class = arg.get_type().get_ptr_type()
        assign = ptr_class + 'CToCpp::Invert(' + arg_name + '[i])'
      result += comment+\
                '\n  std::vector<'+vec_type+' > '+arg_name+'List;'\
                '\n  if ('+arg_name+'Count && *'+arg_name+'Count > 0 && '+arg_name+') {'\
                '\n    for (size_t i = 0; i < *'+arg_name+'Count; ++i) {'\
                '\n      '+arg_name+'List.push_back('+assign+');'\
                '\n    }'\
                '\n  }'
      params.append(arg_name + 'List')
    elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
        arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
        arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
      vec_type = arg.get_type().get_vector_type()
      if arg_type == 'simple_vec_byref_const':
        assign = arg_name + '[i]'
      elif arg_type == 'bool_vec_byref_const':
        assign = arg_name + '[i]?true:false'
      else:
        ptr_class = arg.get_type().get_ptr_type()
        if arg_type == 'refptr_vec_same_byref_const':
          assign = ptr_class + 'CppToC::Revert(' + arg_name + '[i])'
        elif arg_type == 'refptr_vec_diff_byref_const':
          assign = ptr_class + 'CToCpp::Invert(' + arg_name + '[i])'
        elif arg_type == 'rawptr_vec_same_byref_const':
          assign = ptr_class + 'CppToC::UnwrapRaw(' + arg_name + '[i])'
        elif arg_type == 'rawptr_vec_diff_byref_const':
          assign = ptr_class + 'CToCpp::Invert(' + arg_name + '[i]).release()'
      result += comment+\
                '\n  std::vector<'+vec_type+' > '+arg_name+'List;'\
                '\n  if ('+arg_name+'Count > 0) {'\
                '\n    for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
                '\n      '+vec_type+' '+arg_name+'Val = '+assign+';'\
                '\n      '+arg_name+'List.push_back('+arg_name+'Val);'\
                '\n    }'\
                '\n  }'
      params.append(arg_name + 'List')
    else:
      raise Exception('Unsupported argument type %s for parameter %s in %s' %
                      (arg_type, arg_name, name))

  if len(result) != result_len:
    result += '\n'
  result_len = len(result)

  # execution
  result += '\n  // Execute\n  '

  if retval_type != 'none':
    # has a return value
    if retval_type == 'simple' or retval_type == 'bool' or retval_type == 'void*' or retval_type == 'uint8_t*' or \
       retval_type == 'uint32_t*' or retval_type == 'char*' or check_arg_type_is_struct(retval_type):
      result += 'return '
    else:
      result += retval.get_type().get_type()
      result += ' _retval = '

  if isinstance(func.parent, obj_class):
    # virtual and static class methods
    if isinstance(func, obj_function_virtual):
      if cls.get_name() == func.parent.get_name():
        # virtual method for the current class
        result += func.parent.get_name() + 'CppToC::Get(self)->'
      else:
        # virtual method for a parent class
        result += cls.get_name(
        ) + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name() + '*>(self))->'
    else:
      result += func.parent.get_name() + '::'
  result += func.get_name() + '('

  if len(params) > 0:
    result += '\n      ' + ',\n      '.join(params)

  result += ');\n'

  result_len = len(result)

  # parameter restoration
  for arg in args:
    arg_type = arg.get_arg_type()
    arg_name = arg.get_type().get_name()

    comment = '\n  // Restore param: ' + arg_name + '; type: ' + arg_type

    if arg_type == 'simple_byref':
      """"""
    elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr':
      """"""
    elif arg_type == 'struct_byref':
      result += comment+\
                '\n  if ('+arg_name+') {'\
                '\n    '+arg_name+'Obj.DetachTo(*'+arg_name+');'\
                '\n  }'
    elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
      ptr_class = arg.get_type().get_ptr_type()
      if arg_type == 'refptr_same_byref':
        assign = ptr_class + 'CppToC::Invert(' + arg_name + 'Ptr)'
      else:
        assign = ptr_class + 'CToCpp::Revert(' + arg_name + 'Ptr)'
      result += comment+\
                '\n  if ('+arg_name+') {'\
                '\n    if ('+arg_name+'Ptr.get()) {'\
                '\n      if ('+arg_name+'Ptr.get() != '+arg_name+'Orig) {'\
                '\n        *'+arg_name+' = '+assign+';'\
                '\n      }'\
                '\n    } else {'\
                '\n      *'+arg_name+' = nullptr;'\
                '\n    }'\
                '\n  }'
    elif arg_type == 'string_vec_byref':
      result += comment+\
                '\n  cef_string_list_clear('+arg_name+');'\
                '\n  transfer_string_list_contents('+arg_name+'List, '+arg_name+');'
    elif arg_type == 'string_map_single_byref':
      result += comment+\
                '\n  cef_string_map_clear('+arg_name+');'\
                '\n  transfer_string_map_contents('+arg_name+'Map, '+arg_name+');'
    elif arg_type == 'string_map_multi_byref':
      result += comment+\
                '\n  cef_string_multimap_clear('+arg_name+');'\
                '\n  transfer_string_multimap_contents('+arg_name+'Multimap, '+arg_name+');'
    elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
        arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
      if arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref':
        assign = arg_name + 'List[i]'
      elif arg_type == 'refptr_vec_same_byref':
        ptr_class = arg.get_type().get_ptr_type()
        assign = ptr_class + 'CppToC::Invert(' + arg_name + 'List[i])'
      elif arg_type == 'refptr_vec_diff_byref':
        ptr_class = arg.get_type().get_ptr_type()
        assign = ptr_class + 'CToCpp::Revert(' + arg_name + 'List[i])'
      result += comment+\
                '\n  if ('+arg_name+'Count && '+arg_name+') {'\
                '\n    *'+arg_name+'Count = std::min('+arg_name+'List.size(), *'+arg_name+'Count);'\
                '\n    if (*'+arg_name+'Count > 0) {'\
                '\n      for (size_t i = 0; i < *'+arg_name+'Count; ++i) {'\
                '\n        '+arg_name+'[i] = '+assign+';'\
                '\n      }'\
                '\n    }'\
                '\n  }'
    elif arg_type == 'rawptr_vec_diff_byref_const':
      result += comment+\
                '\n  if ('+arg_name+'Count > 0) {'\
                '\n    for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
                '\n      delete '+arg_name+'List[i];'\
                '\n    }'\
                '\n  }'

  if len(result) != result_len:
    result += '\n'
  result_len = len(result)

  if len(result) != result_len:
    result += '\n'
  result_len = len(result)

  # return translation
  if retval_type != 'none' and retval_type != 'simple' and retval_type != 'bool' and retval_type != 'void*' and \
     retval_type != 'uint8_t*' and retval_type != 'uint32_t*' and retval_type != 'char*' and check_arg_type_is_struct(retval_type) == False:
    # has a return value
    result += '\n  // Return type: ' + retval_type
    if retval_type == 'simple' or retval_type == 'bool':
      result += '\n  return _retval;'
    elif retval_type == 'string':
      result += '\n  return _retval.DetachToUserFree();'
    elif retval_type == 'refptr_same':
      ptr_class = retval.get_type().get_ptr_type()
      result += '\n  return ' + ptr_class + 'CppToC::Invert(_retval);'
    elif retval_type == 'refptr_diff':
      ptr_class = retval.get_type().get_ptr_type()
      result += '\n  return ' + ptr_class + 'CToCpp::Revert(_retval);'
    elif retval_type == 'ownptr_same':
      ptr_class = retval.get_type().get_ptr_type()
      result += '\n  return ' + ptr_class + 'CppToC::WrapOwn(std::move(_retval));'
    elif retval_type == 'ownptr_diff':
      ptr_class = retval.get_type().get_ptr_type()
      result += '\n  return ' + ptr_class + 'CToCpp::UnwrapOwn(std::move(_retval));'
    else:
      raise Exception('Unsupported return type %s in %s' % (retval_type, name))

  if len(result) != result_len:
    result += '\n'

  result += '}\n\n'
  return result


def make_cpptoc_function_impl(cls, funcs, prefixname, defined_names):
  impl = ''

  new_list = []
  old_list = get_func_name_list(funcs)

  for func in funcs:
    suffix = ''
    new_list = get_func_name_count(func.get_capi_name(), old_list, new_list)
    if new_list.count(func.get_capi_name()) != 0:
      suffix = str(new_list.count(func.get_capi_name()))
 
    if not prefixname is None:
      name = prefixname + '_' + func.get_capi_name() + suffix 
    else:
      name = func.get_capi_name() + suffix
    impl += make_cpptoc_function_impl_new(cls, name, func, defined_names)

  return impl


def make_cpptoc_virtual_function_impl(header, cls, prefixname, defined_names):
  funcs = []
  funcs.extend(cls.get_virtual_funcs())
  cur_cls = cls
  while True:
    parent_name = cur_cls.get_parent_name()
    if is_base_class(parent_name):
      break
    else:
      parent_cls = header.get_class(parent_name, defined_names)
      if parent_cls is None:
        raise Exception('Class does not exist: ' + parent_name)
      funcs.extend(parent_cls.get_virtual_funcs())
    cur_cls = header.get_class(parent_name, defined_names)

  return make_cpptoc_function_impl(cls, funcs, prefixname, defined_names)


def make_cpptoc_virtual_function_assignment_block(funcs, offset, prefixname):
  new_list = []
  old_list = get_func_name_list(funcs)

  impl = ''
  for func in funcs:
    suffix = ''
    suffix1 = ''
    new_list = get_func_name_count(func.get_capi_name(), old_list, new_list)
    if new_list.count(func.get_capi_name()) != 0:
      suffix = str(new_list.count(func.get_capi_name()))
    elif check_func_name_is_key_work(func.get_capi_name()):
      suffix1 = '0'
    
    name = func.get_capi_name()
    impl += '  GetStruct()->' + offset + name + suffix + suffix1 + ' = ' + prefixname + '_' + name + suffix + ';\n'
  return impl


def make_cpptoc_virtual_function_assignment(header, cls, prefixname,
                                            defined_names):
  impl = make_cpptoc_virtual_function_assignment_block(cls.get_virtual_funcs(),
                                                       '', prefixname)

  cur_cls = cls
  offset = ''
  while True:
    parent_name = cur_cls.get_parent_name()
    offset += 'base.'
    if is_base_class(parent_name):
      break
    else:
      parent_cls = header.get_class(parent_name, defined_names)
      if parent_cls is None:
        raise Exception('Class does not exist: ' + parent_name)
      impl += make_cpptoc_virtual_function_assignment_block(
          parent_cls.get_virtual_funcs(), offset, prefixname)
    cur_cls = header.get_class(parent_name, defined_names)

  return impl


def make_cpptoc_static_function_impl(cls, funcs, defined_names):
  new_list = []
  old_list = get_func_name_list(funcs)

  impl = '#ifdef __cplusplus\n' + \
         'extern "C" {\n' + \
         '#endif // __cplusplus\n\n'

  for func in funcs:
    suffix = ''
    suffix1 = ''
    new_list = get_func_name_count(func.get_capi_name(), old_list, new_list)
    if new_list.count(func.get_capi_name()) != 0:
      suffix = str(new_list.count(func.get_capi_name()))
    func_name = func.get_capi_name() + suffix
    parts = func.get_capi_parts(defined_names, True)
    impl += make_cpptoc_impl_proto(func_name + '_static', func, parts, True) + ' {\n'\
            '  ARK_WEB_CPPTOC_DV_LOG();\n\n'

    retval = func.get_retval()
    retval_type = retval.get_retval_type()
    if retval_type != 'none':
      impl += '  return '
    impl += 'OHOS::ArkWeb::'+ func_name + '('

    params = []
    args = func.get_arguments()
    for arg in args:
      arg_name = arg.get_type().get_name()
      params.append(arg_name)

    if len(params) > 0:
      impl += '\n      ' + ',\n      '.join(params)

    impl += ');\n}\n\n'

  impl += '#ifdef __cplusplus\n' + \
          '}\n' + \
          '#endif // __cplusplus'

  return impl


def make_cpptoc_unwrap_derived(header, cls, base_scoped):
  derived_classes = get_derived_classes(cls, header)

  if base_scoped:
    impl = ['', '']
    for clsname in derived_classes:
      impl[0] += '  if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
                 '    return '+clsname+'CppToC::UnwrapOwn(reinterpret_cast<'+\
                 get_capi_name(clsname, True)+'*>(s));\n'+\
                 '  }\n'
      impl[1] += '  if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
                 '    return '+clsname+'CppToC::UnwrapRaw(reinterpret_cast<'+\
                 get_capi_name(clsname, True)+'*>(s));\n'+\
                 '  }\n'
  else:
    impl = ''
    for clsname in derived_classes:
      impl += '  if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
              '    return '+clsname+'CppToC::Revert(reinterpret_cast<'+\
              get_capi_name(clsname, True)+'*>(s));\n'+\
              '  }\n'
  return impl


def make_cpptoc_impl_file(header, dir_path, dir_name, clsname):
  # structure names that have already been defined
  defined_names = header.get_defined_structs()

  # retrieve the class and populate the defined names
  cls = header.get_class(clsname, defined_names)
  if cls is None:
    raise Exception('Class does not exist: ' + clsname)

  capiname = cls.get_capi_name()
  prefixname = get_capi_name(clsname, False)

  base_class_name = header.get_base_class_name(clsname)
  base_scoped = True if base_class_name == 'ArkWebBaseScoped' else False
  if base_scoped:
    template_class = 'ArkWebCppToCScoped'
  else:
    template_class = 'ArkWebCppToCRefCounted'

  # generate virtual functions
  virtualimpl = make_cpptoc_virtual_function_impl(header, cls, prefixname, defined_names)
  if len(virtualimpl) > 0:
    virtualimpl = '\nnamespace {\n\n' + virtualimpl + '}  // namespace'

  # the current class is already defined for static functions
  defined_names.append(cls.get_capi_name())

  # generate static functions
  staticimpl = make_cpptoc_function_impl(cls, cls.get_static_funcs(), None, defined_names)

  resultingimpl = staticimpl + virtualimpl

  # any derived classes can be unwrapped
  unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped)

  const =  clsname+'CppToC::'+clsname+'CppToC() {\n'
  const += make_cpptoc_virtual_function_assignment(header, cls, prefixname,
                                                   defined_names)
  const += '}\n\n'+ \
           clsname+'CppToC::~'+clsname+'CppToC() {\n'

  const += '}\n\n'

  # determine what includes are required by identifying what translation
  # classes are being used
  includes = format_translation_includes(header, dir_name, const + resultingimpl +
                                         (unwrapderived[0]
                                          if base_scoped else unwrapderived))
  includes += '#include "base/cpptoc/ark_web_cpptoc_macros.h"\n'

  # build the final output
  content = get_copyright()

  content += '\n' + includes + '\n' + 'namespace OHOS::ArkWeb {\n\n' + resultingimpl + '\n'

  parent_sig = template_class + '<' + clsname + 'CppToC, ' + clsname + ', ' + capiname + '>'

  const += make_wrapper_type(clsname, parent_sig)

  content += '\n\n' + const
  content += '\n\n} // namespace OHOS::ArkWeb\n\n'

  if len(cls.get_static_funcs()) > 0:
    staticimpl = make_cpptoc_static_function_impl(cls, cls.get_static_funcs(), defined_names)
    content += staticimpl

  absolute_path = os.path.join(dir_path, prefixname + '_cpptoc.cc')
  return (content, absolute_path)
